/*
** Definitions for limits on the hardware. These will be increased if issues are reported
*/

#define HARDWARE_MAX_CPUS 6
#define HARDWARE_MAX_SOUND 5
#define HARDWARE_MAX_TIMERS 20

enum {
	HARDWARE_RUNNING_CPU,	// CPU is executing
	HARDWARE_RUNNING_SOUND, // Sound is being generated
	HARDWARE_PLAYING_SOUND, // Sound is being output
};

enum {
	HARDWARE_CPU_RUNNING,
	HARDWARE_CPU_YIELDING,
	HARDWARE_CPU_STOPPED,
};

/*
** CHardware, which receives and controls the CPUs, sound devices and timers.
** TODO: Clean up this class. It's an unreadable mess.
*/
class CHardware {
	private: // Emulated components we are in charge of
		ICpu*       cpu[HARDWARE_MAX_CPUS];
		//ISoundDevice* snd[HARDWARE_MAX_SOUND];
		CTimer* timer[HARDWARE_MAX_TIMERS];
		CTimer* mixerupdatetimer;

		double cpu_runtime		  [HARDWARE_MAX_CPUS];
		int cpu_cycles_to_run     [HARDWARE_MAX_CPUS];
		int cpu_cycles_done       [HARDWARE_MAX_CPUS];
		int cpu_idle_frame		  [HARDWARE_MAX_CPUS];
		UINT8 cpu_boost			  [HARDWARE_MAX_CPUS];
		
		double sched_runtime;
		double sched_step;

		int timerfired;
		double clock_div;

		short downmix[2];
		int cpucount;
		//int sndcount;
		int timercount;
		int isInStreamMode; // Driver is playing a stream rather than emulating hardware

		CAudioBuffer* leftstream;
		CAudioBuffer* rightstream;

	private: // Variables
		char speakerCount;  // Speaker count, set up by sound devices.
		int srate;				// Sample rate
		int nsrate;				// System's native sample rate (sample rate usually shouldn't exceed this, if we can, we resample stuff)
		double steptime;
		double uptime;		// System run time in seconds
		int frame_samples; // how long we're running for
	
	// CPU Scheduler
	private:
		void ExecCPUTimeslice();
		void CPUClose();


	private:
		void UpdateScheduler();
		void RunCPUFrame();
		void RunSoundFrame();
		void RunTimerFrame();

	public: // Timer callback
		void TimerFired() { timerfired = 1; }

	public: // Device assignment
		int AddCpu(ICpu* cpu);
		int AddSound(ISoundDevice* dev);
		int AddTimer(CTimer* timer);

	public: // Mixer can be seen by other devices
		CMixer* mixer;
		void ChangeScheduler(double framelen, double step);

	public: // Passed onto Mixer
		int GetSpeakerCount();
		int GetSampleRate() { return srate; }

	public: // Execution control interface
		double RunAudioFramesUntilSound();
		UINT32 RunAudioFrames(INT16* buf, UINT32 bufsize);
		void Reset(); // Soft Reset

	public: // Constructor/destructor
		void SetOutput(UINT32 sr);
		void Shutdown();
		CHardware(int srate);
};